package org.bookr.console.controller;

import org.bookr.engine.model.Book;
import org.bookr.engine.model.Category;
import org.bookr.engine.service.BookrService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.propertyeditors.CustomCollectionEditor;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ValidationUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import java.beans.PropertyEditorSupport;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;

/**
 * @author Pawel Tomaszewski
 */
@Controller
public class BookController {
    private Logger logger = LoggerFactory.getLogger(BookController.class);
    private BookrService bookrService;

    @RequestMapping(value = "/book/create", method = RequestMethod.GET)
    public ModelAndView createBookForm() {
        ModelAndView result = new ModelAndView("console.createBook");
        result.addObject("status", "console.webapp.status.fillForm");
        result.addObject("book", new Book());
        result.addObject("allCategories", bookrService.listCategories());
        result.addObject("allAuthors", bookrService.listAuthors());
        return result;
    }

    @RequestMapping(value = "/book/create", method = RequestMethod.POST)
    public ModelAndView processCreateBookForm(@ModelAttribute Book book, BindingResult bindingResult) {
        ModelAndView results = new ModelAndView("console.createBook");
        ValidationUtils.rejectIfEmptyOrWhitespace(bindingResult, "title", "console.webapp.formValidation.emptyField");
        ValidationUtils.rejectIfEmptyOrWhitespace(bindingResult, "description", "console.webapp.formValidation.emptyField");
        if(bindingResult.hasErrors()) {
            results.addObject("status", "console.webapp.status.correctForm");
            results.addObject("allCategories", bookrService.listCategories());
            results.addObject("allAuthors", bookrService.listAuthors());
            logger.debug("There was some errors: " + bindingResult.getAllErrors());
        } else {
            Date now = new Date();
            book.setCreatedDate(now);
            book.setLastUpdateDate(now);
            String id = bookrService.updateBook(book);
            results.addObject("status", "console.webapp.status.createSuccess");
            results.addObject("book", bookrService.loadBook(id));
            results.setViewName("console.book");
        }
        return results;
    }

    @RequestMapping(value = "/book/{id}/edit", method = RequestMethod.GET)
    public ModelAndView editBookForm(@PathVariable String id) {
        ModelAndView results = new ModelAndView("console.editBook");
        results.addObject("status", "console.webapp.status.fillForm");
        results.addObject("book", bookrService.loadBook(id));
        results.addObject("allCategories", bookrService.listCategories());
        results.addObject("allAuthors", bookrService.listAuthors());
        return results;
    }

    @RequestMapping(value = "/book/{id}/edit", method = RequestMethod.POST)
    public ModelAndView processEditBookForm(@PathVariable String id,
                                            @ModelAttribute Book book, BindingResult bindingResult) {
        ModelAndView results = new ModelAndView("console.editBook");
        ValidationUtils.rejectIfEmptyOrWhitespace(bindingResult, "title", "console.webapp.formValidation.emptyField");
        ValidationUtils.rejectIfEmptyOrWhitespace(bindingResult, "description", "console.webapp.formValidation.emptyField");
        if(bindingResult.hasErrors()) {
            results.addObject("status", "console.webapp.status.correctForm");
            results.addObject("allCategories", bookrService.listCategories());
            results.addObject("allAuthors", bookrService.listAuthors());
        } else {
            book.setLastUpdateDate(new Date());
            bookrService.updateBook(book);
            results.addObject("status", "console.webapp.status.editSuccess");
            results.addObject("book", bookrService.loadBook(id));
            results.setViewName("console.book");
        }
        return results;
    }

    @RequestMapping("/books")
    public ModelAndView listBooks() {
        ModelAndView results = new ModelAndView("console.books");
        results.addObject("status", "console.webapp.status.ok");
        results.addObject("books", bookrService.listBooks());
        return results;
    }

    @RequestMapping("/book/{id}")
    public ModelAndView showBook(@PathVariable String id) {
        ModelAndView results = new ModelAndView("console.book");
        results.addObject("status", "console.webapp.status.ok");
        results.addObject("book", bookrService.loadBook(id));
        return results;
    }

    @RequestMapping("/book/{id}/remove")
    public ModelAndView removeBook(@PathVariable String id) {
        ModelAndView results = new ModelAndView("redirect:/books");
        bookrService.removeBook(bookrService.loadBook(id));
        return results;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss");
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
        binder.registerCustomEditor(Set.class, "authors", new CustomCollectionEditor(Set.class) {
            @Override
            public Object convertElement(Object element) {
                if(element instanceof String)
                    return bookrService.loadAuthor((String) element);
                return null;
            }
        });
        binder.registerCustomEditor(Category.class, "category", new PropertyEditorSupport() {
            @Override
            public void setAsText(String id) {
                setValue(bookrService.loadCategory(id));
            }
        });
    }

    public BookrService getBookrService() {
        return bookrService;
    }

    public void setBookrService(BookrService bookrService) {
        this.bookrService = bookrService;
    }
}
